#include <Windows.h>
#include <tchar.h>
#include <assert.h>

#define		WM_TEST					(WM_USER + 1002)

DWORD dwTickCount;


struct SInfo {
	UINT	nParam;
	const TCHAR* szSendWay;
};

SInfo Info[] = { 
	{0, _T("PostMessage")},			{1, _T("SendMessageCallBack")},		{2, _T("SendNotifyMessage")},
	{3, _T("SendMessageTimeout")},  {4, _T("SendMessage")},				{5, _T("SendMessage")}
};

TCHAR szContext[10 * MAX_PATH] = {0};

void CALLBACK TestMsgProc(HWND hWnd, UINT nMessage, ULONG_PTR lpData, LRESULT lResult)
{
	TCHAR szTmp[128];
	_stprintf(szTmp, _T("SendMessageCallback callback method result: %d\n"), lResult);

	_tcscat(szContext, szTmp);
	OutputDebugString(szTmp);
}

DWORD CALLBACK ThreadProc(LPVOID lpData)
{
	HWND hMainWnd = *(HWND*)lpData;
	TCHAR szTmp[128];
	DWORD dwRes= 0;
	
	for (int ii = 0; ii < sizeof(Info) / sizeof(*Info); ii++)
	{
		switch (ii)
		{
			case 0:		PostMessage(hMainWnd, WM_TEST, Info[ii].nParam, 0);								break;
			case 1:		SendMessageCallback(hMainWnd, WM_TEST, Info[ii].nParam, 0, TestMsgProc, 0);		break;
			case 2:		SendNotifyMessage(hMainWnd, WM_TEST, Info[ii].nParam, 0);						break;
			case 3:		SendMessageTimeout(hMainWnd, WM_TEST, Info[ii].nParam, 0, 0, 1000, &dwRes);		break;
			case 4:		break; //SendMessage(hMainWnd, WM_TEST, Info[ii].nParam, 0);								break;
			//case 5:		SendMessage(hMainWnd, WM_TEST, Info[ii].nParam, 0);								break;
		}
		OutputDebugString(_T("\n===================================================\n"));
	
		_stprintf(szTmp, _T("Create thread to here(%s), spend time: %d  wparam = %d\n"),
				  Info[ii].szSendWay, GetTickCount() - dwTickCount, Info[ii].nParam);

		//_tcscat(szContext, szTmp);
		OutputDebugString(szTmp);
	}
	
	return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{	
	static const UINT IDC_BTNSEND		= 1001;
	static const UINT IDC_BTNQUIT		= 1002;

	static HANDLE hThread;

	static TCHAR szContent[128];
	switch (nMsg)
	{
		case WM_CREATE:
		{
			dwTickCount = GetTickCount();
			hThread = CreateThread(NULL, NULL, ThreadProc, &hWnd, NULL, 0);
		
			CreateWindow(_T("STATIC"), _T("See Output infomation"), WS_VISIBLE|WS_CHILD, 0, 0, 500, 50, hWnd, (HMENU)0, NULL, 0);
			break;
		}
		case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hDC = BeginPaint(hWnd, &ps);
			RECT rtClient;
			GetClientRect(hWnd, &rtClient);
			DrawText(hDC, szContent, -1, &rtClient, DT_LEFT|DT_SINGLELINE|DT_VCENTER);
			EndPaint(hWnd, &ps);
			break;
		}
case WM_TEST:
{
	if (5 == wParam)
	{
		OutputDebugString(szContext);
	}

	Sleep(2000);
	TCHAR szTmp[128];			
	_stprintf(szTmp, _T("Recieve this message from \"%s\" sent, wparam: %d  \n"), Info[wParam].szSendWay, wParam);	
	OutputDebugString(szTmp);
	//_tcscat(szContext, szTmp);


	return 100;
}
		case WM_CLOSE:
		{
			PostQuitMessage(0);
			break;
		}
		default:
			return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
	}
	
	return 0;
}

//////////////////////////////////////////////////////////////////////////
bool RegisterWndClass(const TCHAR* szClsName, WNDPROC fnWndProc)
{
	WNDCLASSEX wcs		= {0};
	wcs.cbSize			= sizeof(WNDCLASSEX);
	wcs.hbrBackground	= (HBRUSH)GetStockObject(COLOR_APPWORKSPACE);
	wcs.lpszClassName	= szClsName;
	wcs.lpfnWndProc		= fnWndProc;
	wcs.hCursor			= LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
	wcs.hIcon			= LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_APPLICATION));
	wcs.style			= CS_VREDRAW|CS_HREDRAW;
	
	return (0 != RegisterClassEx(&wcs));
}

//////////////////////////////////////////////////////////////////////////
HWND CreateWnd(const TCHAR* szClsName, const TCHAR* szWndCaption, HWND hParent = NULL, 
			   DWORD dwStyle = WS_POPUP|WS_VISIBLE|WS_SYSMENU|WS_CAPTION, 
			   DWORD dwStyleEx = 0)
{
	if (NULL != szClsName)
	{
		HWND hWnd = CreateWindowEx(dwStyleEx, szClsName, szWndCaption, dwStyle, 
			                       0, 0, 800, 480, NULL, NULL, GetModuleHandle(NULL), NULL);
	
		if (NULL != hWnd && IsWindow(hWnd))
		{
			return hWnd;
		}
	}
	return NULL;
}

//////////////////////////////////////////////////////////////////////////
void RunMessageLoop()
{
	MSG Msg;
	while (true)
	{
		while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
		{
			if (WM_QUIT == Msg.message)
			{
				return;
			}

			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		}
	}
}

//////////////////////////////////////////////////////////////////////////
BOOL WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR szCmdLine, int nShowCmd)
{
	const TCHAR* szClsName		= _T("Win32App");
	const TCHAR* szWndCaption	= _T("Demo0052");

	if (RegisterWndClass(szClsName, WndProc))
	{
		if (NULL != CreateWnd(szClsName, szWndCaption))
		{
			RunMessageLoop();
		}
	}

	return TRUE;
}
